class Subject {
    private observers: Observer[] = [];
    private state: number = -Infinity;
    public getState(): number {
        return this.state;
    }
    public setState(state: number): void {
        this.state = state;
        this.notifyObservers();
    }
    public attach(observer: Observer): void {
        this.observers.push(observer);
    }
    public detach(observer: Observer): void {
        const index = this.observers.indexOf(observer);
        if (index !== -1) {
            this.observers.splice(index, 1);
        }
    }
    public notifyObservers(): void {
        this.observers.forEach(observer => observer.update(this.state));
    }
}

abstract class Observer {
    protected subject: Subject | null = null;
    public abstract update(state: number): void;
}

class BinaryObserver extends Observer {
    public constructor(subject: Subject) {
        super();
        this.subject = subject;
        this.subject.attach(this);
    }
    public override update(): void {
        const state: string = (this.subject as Subject).getState().toString(2);
        console.log(`Binary string: ${state}`)
    }
}

class HexaObserver extends Observer {
    public constructor(subject: Subject) {
        super();
        this.subject = subject;
        this.subject.attach(this);
    }
    public override update(): void {
        const state: string = (this.subject as Subject).getState().toString(16);
        console.log(`Hex string: ${state}`)
    }
}

class OctalObserver extends Observer {
    public constructor(subject: Subject) {
        super();
        this.subject = subject;
        this.subject.attach(this);
    }
    public override update(): void {
        const state: string = (this.subject as Subject).getState().toString(8);
        console.log(`Octal string: ${state}`)
    }
}

function main() {
    const subject: Subject = new Subject();
    const observer1: Observer = new BinaryObserver(subject);
    const observer2: Observer = new HexaObserver(subject);
    const observer3: Observer = new OctalObserver(subject);
    console.log('State Changed to 10');
    subject.setState(10);
    subject.detach(observer1);
    console.log('State Changed to 15');
    subject.setState(15);
    subject.detach(observer2);
    console.log('State Changed to 20');
    subject.setState(20);
    subject.detach(observer3);
    console.log('State Changed to 25');
    subject.setState(25);
    console.log(`Current state: ${subject.getState()}`);
}

main();
